home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / HPACK78S.ZIP / unix.c < prev    next >
C/C++ Source or Header  |  1992-11-30  |  21KB  |  802 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                              UNIX-Specific Routines                        *
  7. *                             UNIX.C  Updated 12/02/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *         Copyright 1991-2  Stuart A. Woolford and Peter C. Gutmann.            *
  15. *                            All rights reserved                                *
  16. *                                                                            *
  17. ****************************************************************************/
  18.  
  19. /*    You press the keys with no effect,
  20.     Your mode is not correct.
  21.     The screen blurs, your fingers shake;
  22.     You forgot to press escape.
  23.     Can't insert, can't delete,
  24.     Cursor keys won't repeat.
  25.     You try to quit, but can't leave,
  26.     An extra "bang" is all you need.
  27.  
  28.     You think it's neat to type an "a" or an "i"--
  29.     Oh yeah?
  30.     You won't look at emacs, no you'd just rather die
  31.     You know you're gonna have to face it;
  32.     You're addicted to vi!
  33.  
  34.     You edit files one at a time;
  35.     That doesn't seem too out of line?
  36.     You don't think of keys to bind--
  37.     A meta key would blow your mind.
  38.     H, J, K, L?  You're not annoyed?
  39.     Expressions must be a Joy!
  40.     Just press "f", or is it "t"?
  41.     Maybe "n", or just "g"?
  42.  
  43.     Oh--You think it's neat to type an "a" or an "i"--
  44.     Oh yeah?
  45.     You won't look at emacs, no you'd just rather die
  46.     You know you're gonna have to face it;
  47.     You're addicted to vi!
  48.  
  49.     Might as well face it,
  50.     You're addicted to vi!
  51.     You press the keys without effect,
  52.     Your life is now a wreck.
  53.     What a waste!  Such a shame!
  54.     And all you have is vi to blame.
  55.  
  56.     Oh--You think it's neat to type an "a" or an "i"--
  57.     Oh yeah?
  58.     You won't look at emacs, no you'd just rather die
  59.     You know you're gonna have to face it;
  60.     You're addicted to vi!
  61.  
  62.     Might as well face it,
  63.     You're addicted to vi!
  64.  
  65.         - Chuck Musciano
  66.  
  67.     YOU CAN HAVE MY vi WHEN YOU PRY IT FROM MY COLD DEAD HANDS
  68.  
  69.         - Stuart Woolford */
  70.  
  71. #include <ctype.h>
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <string.h>
  75. #include "defs.h"
  76. #include "error.h"
  77. #include "frontend.h"
  78. #include "hpacklib.h"
  79. #include "system.h"
  80. #include "tags.h"
  81. #include "io/hpackio.h"
  82.  
  83. /* The extra routines needed by each variation of Unix:
  84.  
  85.    AIX                            strlwr    strnicmp
  86.    AIX386                        strlwr    strnicmp
  87.    AIX370                        strlwr    strnicmp
  88.    IRIX            memmove    rename    strlwr    strnicmp
  89.    ISC
  90.    LINUX                        strlwr    strnicmp
  91.    MINT                ?        ?        ?        ?
  92.    POSIX
  93.    SUNOS        memmove                    strnicmp
  94.    SVR4                            strlwr    strnicmp
  95.    ULTRIX                        strlwr    strnicmp
  96.    ULTRIX_OLD    memmove            strlwr    strnicmp */
  97.  
  98. /* Get an input character, no echo */
  99.  
  100. #if defined( POSIX ) || defined( SVR4 ) || defined( IRIX )
  101.  
  102. #include <termios.h>
  103.  
  104. int hgetch( void )
  105.     {
  106.     struct termios ttyInfo;
  107.     FD ttyFD = ERROR;
  108.     char ch;
  109.  
  110.     /* Flush all pending output */
  111.     fflush( stdout );
  112.  
  113.     /* Turn echo off */
  114.     if( isatty( STDERR ) && ( ttyFD = hopen( ttyname( STDERR ), O_RDWR ) ) != ERROR )
  115.         {
  116.         tcgetattr( ttyFD, &ttyInfo );
  117. #if defined( IRIX ) || defined( POSIX )
  118.         ttyInfo.c_lflag &= ~ECHO;
  119.         ttyInfo.c_lflag &= ~ICANON;
  120. #else
  121.         ttyInfo.c_lflags &= ~ECHO;
  122.         ttyInfo.c_lflags |= CBREAK;
  123. #endif /* IRIX || POSIX */
  124.         tcsetattr( ttyFD, TCSANOW, &ttyInfo );
  125.         }
  126.  
  127.     /* Get the character */
  128.     read( ttyFD, &ch, 1 );
  129.  
  130.     /* Turn echo on again if it was off */
  131.     if( ttyFD != ERROR )
  132.         {
  133.         tcgetattr( ttyFD, &ttyInfo );
  134. #if defined( IRIX ) || defined( POSIX )
  135.         ttyInfo.c_lflag |= ECHO;
  136.         ttyInfo.c_lflag |= ICANON;
  137. #else
  138.         ttyInfo.c_lflags |= ECHO;
  139.         ttyInfo.c_lflags &= ~CBREAK;
  140. #endif /* IRIX || POSIX */
  141.         tcsetattr( ttyFD, TCSANOW, &ttyInfo );
  142.         }
  143.  
  144.     return( ch );
  145.     }
  146.  
  147. #else
  148.  
  149. #include <sgtty.h>
  150.  
  151. int hgetch( void )
  152.     {
  153.     struct sgttyb ttyInfo;
  154.     FD ttyFD = ERROR;
  155.     char ch;
  156.  
  157.     /* Flush all pending output */
  158.     fflush( stdout );
  159.  
  160.     /* Turn echo off */
  161.     if( isatty( STDERR ) && ( ttyFD = hopen( ttyname( STDERR ), O_RDWR ) ) != ERROR )
  162.         {
  163.         gtty( ttyFD, &ttyInfo );
  164.         ttyInfo.sg_flags &= ~ECHO;
  165.         ttyInfo.sg_flags |= CBREAK;
  166.         stty( ttyFD, &ttyInfo );
  167.         }
  168.  
  169.     /* Get the character */
  170.     read( ttyFD, &ch, 1 );
  171.  
  172.     /* Turn echo on again if it was off */
  173.     if( ttyFD != ERROR )
  174.         {
  175.         gtty( ttyFD, &ttyInfo );
  176.         ttyInfo.sg_flags |= ECHO;
  177.         ttyInfo.sg_flags &= ~CBREAK;
  178.         stty( ttyFD, &ttyInfo );
  179.         }
  180.  
  181.     return( ch );
  182.     }
  183. #endif /* POSIX || SVR4 || IRIX */
  184.  
  185. #if 0        /* Last-ditch code if all else fails */
  186. int hgetch( void )
  187.     {
  188.     char ch;
  189.  
  190.     system( "/bin/stty +raw" );
  191.     ch = getchar();
  192.     system( "/bin/stty +edit" );
  193.     return( ch );
  194.     }
  195. #endif /* 0 */
  196.  
  197. #ifdef POSIX
  198.  
  199. /* Memory handling functions - need special-case code for QNX to handle
  200.    64K memory blocks */
  201.  
  202. #include <sys/seginfo.h>
  203. #include <i86.h>
  204.  
  205. static unsigned int segmentBase;
  206. static void *segmentPtr = NULL;
  207.  
  208. void *hmalloc( const unsigned long size )
  209.     {
  210.     if( size > 0x0000FFFFL )
  211.         {
  212.         /* Try and allocate a 64K block from the system */
  213.         if( ( segmentBase = qnx_segment_alloc( size ) ) == 0xFFFF )
  214.             return( segmentPtr = NULL );
  215.         segmentPtr = MK_FP( segmentBase, 0 );
  216.         return( segmentPtr );
  217.         }
  218.     else
  219.         return( malloc( ( size_t ) size ) );
  220.     }
  221.  
  222. void *hrealloc( void *buffer, const unsigned long size )
  223.     {
  224.     return( realloc( buffer, ( size_t ) size ) );
  225.     }
  226.  
  227. void hfree( void *buffer )
  228.     {
  229.     if( buffer == segmentPtr )
  230.         qnx_segment_free( segmentBase );
  231.     else
  232.         free( buffer );
  233.     }
  234.  
  235. #endif /* POSIX */
  236.  
  237. /* Set a file's timestamp */
  238.  
  239. void setFileTime( const char *fileName, const LONG fileTime )
  240.     {
  241.     struct utimbuf timeStamp;
  242.  
  243.     /* For now we just set the update time the same as the access time */
  244.     timeStamp.actime = timeStamp.modtime = fileTime;
  245.     utime( fileName, &timeStamp );
  246.     }
  247.  
  248. #ifdef NEED_RENAME
  249.  
  250. /* Rename a file */
  251.  
  252. int rename( const char *srcFile, const char *destFile )
  253.     {
  254.     if( link( srcFile, destFile ) == IO_ERROR )
  255.         return( IO_ERROR );
  256.     return( unlink( srcFile ) );
  257.     }
  258.  
  259. #endif /* NEED_RENAME */
  260.  
  261. /* Create a file.  A custom version is necessary since creating the file
  262.    doesn't give read access to it, so we must open it, close it, and reopen
  263.    it with read access enabled */
  264.  
  265. int hcreat( const char *filePath, const int attr )
  266.     {
  267.     FD theFD;
  268.  
  269.     if( ( theFD = creat( filePath, attr ) ) != IO_ERROR )
  270.         {
  271.         close( theFD );
  272.         return( open( filePath, O_RDWR | S_DENYRDWR | A_SEQ ) );
  273.         }
  274.     else
  275.         return( IO_ERROR );
  276.     }
  277.  
  278. /* Create a directory */
  279.  
  280. int hmkdir( const char *dirName, const int mode )
  281.     {
  282.     int oldUmask = umask( mode ^ 0777 ), retVal, newMode = mode;
  283.  
  284.     /* We have to be clever with umask here since if no x bits are set
  285.        noone will be able to access the directory, so we always give the
  286.        owner an x bit in MKDIR_ATTR.  Also if umask has group or other r
  287.        enabled we give them x as well */
  288.     if( !( oldUmask & UNIX_ATTR_GROUP_R ) )
  289.         newMode |= UNIX_ATTR_GROUP_X;
  290.     if( !( oldUmask & UNIX_ATTR_OTHER_R ) )
  291.         newMode |= UNIX_ATTR_OTHER_X;
  292.  
  293.     if( sysSpecFlags & SYSPEC_NOUMASK )
  294.         umask( newMode ^ 0777 );    /* Make sure umask doesn't interfere */
  295.     else
  296.         umask( oldUmask );
  297.     retVal = mkdir( dirName, newMode );
  298.     umask( oldUmask );                /* Restore original umask */
  299.  
  300.     return( retVal );
  301.     }
  302.  
  303. /* Change a file's attributes */
  304.  
  305. int hchmod( const char *filePath, int mode )
  306.     {
  307.     int oldUmask, retVal;
  308.  
  309.     /* Check whether we should override the umask */
  310.     if( sysSpecFlags & SYSPEC_NOUMASK )
  311.         {
  312.         /* Make sure the umask doesn't interfere when we change the file's
  313.            attributes */
  314.         oldUmask = umask( mode ^ 0777 );
  315.         retVal = chmod( filePath, mode );
  316.         umask( oldUmask );                    /* Restore original umask */
  317.         }
  318.     else
  319.         retVal = chmod( filePath, mode );
  320.  
  321.     return( retVal );
  322.     }
  323.  
  324. /* opendir(), readdir(), closedir() for those systems which don't have them.
  325.    If anyone ever uses this code let me know so I can open a bottle of
  326.    champagne or something */
  327.  
  328. #if 0
  329. #include <fcntl.h>
  330. #include <sys/types.h>
  331.  
  332. #include <dir.h>
  333.  
  334. #define DIRBUFSIZE        512
  335.  
  336. typedef struct {
  337.                struct stat d_stat;        /* stat() info for dir */
  338.                char d_name[ MAX_FILENAME ];
  339.                } DIRECT;
  340.  
  341. typedef struct {
  342.                int dd_fd;                /* This directories' FD */
  343.                int dd_loc;                /* Index into buffer of dir info */
  344.                int dd_size;                /* No. of entries in buffer */
  345.                char dd_buf[ DIRBUFSIZE ];    /* Buffer of dir entries */
  346.                } DIR;
  347.  
  348. DIR *opendir( const char *dirName )
  349.     {
  350.     DIR *dirPtr;
  351.     FD dirFD;
  352.  
  353.     /* Try and open directory corresponding to dirName */
  354.     if( ( dirFD = hopen( dirName, O_RDONLY ) ) != FILE_ERROR )
  355.         {
  356.         /* Allocate room for directory information */
  357.         if( ( dirPtr = ( DIR * ) hmalloc( sizeof( DIR ) ) ) != NULL )
  358.             {
  359.             /* Set up directory information */
  360.             dirPtr->dd_fd = dirFD;
  361.             dirPtr->dd_loc = 0;
  362.             dirPtr->dd_size = 0;
  363.             return( dirPtr );
  364.             }
  365.         hclose( dirFD );
  366.         }
  367.     return( NULL );
  368.     }
  369.  
  370. /* Read out the next directory entry */
  371.  
  372. DIRECT *readdir( DIR *dirPtr )
  373.     {
  374.     static DIRECT dirInfo;            /* Dir.info as we want it set out */
  375.     struct direct *diskDirInfo;        /* Dir.info as stored on disk */
  376.  
  377.     /* Grovel through dir.entries until we find a non-deleted file */
  378.     do
  379.         {
  380.         /* Check if we need to read in more of dir */
  381.         if( dirPtr->dd_loc >= dirPtr->dd_size )
  382.             {
  383.             /* Yes, read in next load of info */
  384.             dirPtr->dd_loc = 0;
  385.             if( ( dirPtr->dd_size = hread( dirPtr->dd_fd, dirPtr->dd_buf, DIRBUFSIZE ) ) == FILE_ERROR )
  386.                 /* Out of directory, return NULL dirinfo */
  387.                 return( NULL );
  388.             }
  389.  
  390.         /* Extract this directory entry and point to next location in buffer */
  391.         diskDirInfo = ( struct direct * ) ( dirPtr->dd_buf + dirPtr->dd_loc );
  392.         dirPtr->dd_loc += sizeof( struct direct );
  393.         }
  394.     while( diskDirInfo->d_ino == 0 );
  395.  
  396.     /* Move info across to struct as we want it */
  397.     strncpy( dirInfo.d_name, diskDirInfo->d_name, NAMEINDIR_LEN );
  398.     dirInfo.d_name[ NAMEINDIR_LEN ] = '\0';
  399.     stat( dirInfo.d_name, &dirInfo.d_stat );
  400.  
  401.     return( &dirInfo );
  402.     }
  403.  
  404. /* End opendir() functions */
  405.  
  406. void closedir( DIR *dirPtr )
  407.     {
  408.     hclose( dirPtr->dd_fd );
  409.     hfree( dirPtr );
  410.     }
  411. #endif /* 0 */
  412.  
  413. /* Find the first/next file in a directory */
  414.  
  415. BOOLEAN findFirst( const char *pathName, const ATTR fileAttr, FILEINFO *fileInfo )
  416.     {
  417.     char dirPath[ MAX_PATH ];
  418.     int pos;
  419.  
  420.     /* Start at first entry in this directory */
  421.     fileInfo->matchAttr = fileAttr;
  422.  
  423.     strcpy( dirPath, pathName );
  424.     if( !*dirPath )
  425.         {
  426.         /* No pathname, search current directory */
  427.         *dirPath = '.' ;
  428.         dirPath[ 1 ] = '\0';
  429.         }
  430.  
  431.     /* Check whether we want to match all files in a directory or one
  432.        particular file */
  433.     if( dirPath[ strlen( dirPath ) - 1 ] == '.' )
  434.         {
  435.         /* Try and open directory */
  436.         if( ( fileInfo->dirBuf = opendir( dirPath ) ) == NULL )
  437.             return( FALSE );
  438.         dirPath[ strlen( dirPath ) - 1 ] = '\0';    /* Zap '.' */
  439.         strcpy( fileInfo->dName, dirPath );
  440.  
  441.         /* Pull file information out of directory */
  442.         return( findNext( fileInfo ) );
  443.         }
  444.     else
  445.         {
  446.         /* Handling one particular file, just stat it */
  447.         fileInfo->dirBuf=NULL;
  448.         for( pos = strlen( dirPath ) - 1; pos != 0 && dirPath[ pos ] != SLASH; \
  449.              pos-- );
  450.         strcpy( fileInfo->fName, dirPath + pos );
  451.         if( stat( dirPath, &fileInfo->statInfo ) != ERROR )
  452.             {
  453.             fileInfo->fTime = fileInfo->statInfo.st_mtime;
  454.             fileInfo->fSize = fileInfo->statInfo.st_size;
  455.             return TRUE;
  456.             }
  457.         else
  458.             return FALSE;
  459.         }
  460.     }
  461.  
  462. BOOLEAN findNext( FILEINFO *fileInfo )
  463.     {
  464.     struct dirent *dirinfo;
  465.     char dirPath[ MAX_PATH ];
  466.  
  467.     do
  468.         {
  469.         /* Grovel through the directory skipping deleted and non-matching files */
  470.         if( ( dirinfo = readdir( fileInfo->dirBuf ) ) == NULL )
  471.             return( FALSE );
  472.  
  473.         /* Fill out fileInfo fields.  Some systems may have the stat info
  474.            available after the readdir() call, but we have to assume the
  475.            worst for the portable version */
  476.         strncpy( fileInfo->fName, dirinfo->d_name, MAX_FILENAME );
  477.         fileInfo->fName[ MAX_FILENAME ] = 0;
  478.         if( strlen( fileInfo->dName ) + strlen( fileInfo->fName ) > MAX_PATH )
  479.             error( PATH_s__TOO_LONG, dirPath );
  480.         strcpy( dirPath, fileInfo->dName );            /* Copy dirpath */
  481.         strcat( dirPath, fileInfo->fName );            /* Add filename */
  482.         stat( dirPath, &fileInfo->statInfo );
  483.         fileInfo->fTime = fileInfo->statInfo.st_mtime;
  484.         fileInfo->fSize = fileInfo->statInfo.st_size;
  485.         }
  486.     /* Sometimes we only want to match files, not directories */
  487.     while( ( fileInfo->matchAttr == ALLFILES ) ? \
  488.            ( ( fileInfo->statInfo.st_mode & S_IFMT ) == S_IFDIR ) : 0 );
  489.  
  490.     return( TRUE );
  491.     }
  492.  
  493. /* End findFirst/Next() for this directory */
  494.  
  495. void findEnd( FILEINFO *fileInfo )
  496.     {
  497.     if( fileInfo->dirBuf != NULL )
  498.         closedir( fileInfo->dirBuf );
  499.     }
  500.  
  501. /* Get the screen size.  The environment variables $LINES and $COLUMNS will
  502.    be used if they exist.  If not, then the TIOCGWINSZ call to ioctl() is
  503.    used (if it is defined).  If not, then the TIOCGSIZE call to ioctl() is
  504.    used (if it is defined).  If not, then the WIOCGETD call to ioctl() is
  505.    used (if it is defined).  If not, then get the info from terminfo/termcap
  506.    (if it is there).  Otherwise, assume we have a 24x80 model 33 */
  507.  
  508. #define DEFAULT_ROWS        24
  509. #define DEFAULT_COLS        80
  510.  
  511. /* Try to access terminfo through the termcap-interface in the curses library
  512.    (which requires linking with -lcurses) or use termcap directly (which
  513.    requires linking with -ltermcap) */
  514.  
  515. #ifndef USE_TERMCAP
  516.   #if defined( USE_TERMINFO ) || defined( USE_CURSES )
  517.     #define USE_TERMCAP
  518.   #endif /* USE_TERMINFO || USE_CURSES */
  519. #endif /* USE_TERMCAP */
  520.  
  521. #ifdef USE_TERMCAP
  522.   #define TERMBUFSIZ    1024
  523.   #define UNKNOWN_TERM    "unknown"
  524.   #define DUMB_TERMBUF    "dumb:co#80:hc:"
  525.  
  526.   extern int tgetent(), tgetnum();
  527. #endif /* USE_TERMCAP */
  528.  
  529. /* Try to get TIOCGWINSZ from termios.h, then from sys/ioctl.h */
  530.  
  531. #include <termios.h>
  532. #if !defined( TIOCGWINSZ ) && !defined( TIOCGSIZE ) && !defined( WIOCGETD )
  533.   #include <sys/ioctl.h>
  534. #endif /* !( TIOCGWINSIZ || TIOCGSIZE || WIOCGETD ) */
  535.  
  536. /* If we still don't have TIOCGWINSZ (or TIOCGSIZE) try for WIOCGETD */
  537.  
  538. #if !defined( TIOCGWINSZ ) && !defined( TIOCGSIZE ) && !defined( WIOCGETD )
  539.   #include <sgtty.h>
  540. #endif /* !( TIOCGWINSZ || TIOCGSIZE || WIOCGETD ) */
  541.  
  542. void getScreenSize( void )    /* Rot bilong kargo */
  543.     {
  544.     char *envLines, *envColumns;
  545.     long rowTemp = 0, colTemp = 0;
  546. #ifdef USE_TERMCAP
  547.     char termBuffer[ TERMBUFSIZ ], *termInfo;
  548. #endif /* USE_TERMCAP */
  549. #ifdef TIOCGWINSZ
  550.     struct winsize windowInfo;
  551. #else
  552.   #ifdef TIOCGSIZE
  553.     struct ttysize windowInfo;
  554.   #else
  555.     #ifdef WIOCGETD
  556.       struct uwdata windowInfo;
  557.     #endif /* WIOCGETD */
  558.   #endif /* TIOCGSIZE */
  559. #endif /* TIOCGSIZE */
  560.  
  561.     screenHeight = screenWidth = 0;
  562.  
  563.     /* Make sure that we're outputting to a terminal */
  564.     if( !isatty( fileno( stderr ) ) )
  565.         {
  566.         screenHeight = DEFAULT_ROWS;
  567.         screenWidth = DEFAULT_COLS;
  568.         return;
  569.         }
  570.  
  571.     /* LINES & COLUMNS environment variables override everything else */
  572.     envLines = getenv( "LINES" );
  573.     if( envLines != NULL && ( rowTemp = atol( envLines ) ) > 0 )
  574.         screenHeight = ( int ) rowTemp;
  575.  
  576.     envColumns = getenv( "COLUMNS" );
  577.     if( envColumns != NULL && ( colTemp = atol( envColumns ) ) > 0 )
  578.         screenWidth = ( int ) colTemp;
  579.  
  580. #ifdef TIOCGWINSZ
  581.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  582.     if( ( !screenHeight || !screenWidth ) && ioctl( fileno( stderr ), TIOCGWINSZ, &windowInfo ) != -1 )
  583.         {
  584.         if( !screenHeight && windowInfo.ws_row > 0 )
  585.             screenHeight = ( int ) windowInfo.ws_row;
  586.  
  587.         if( !screenWidth && windowInfo.ws_col > 0 )
  588.             screenWidth = ( int ) windowInfo.ws_col;
  589.         }
  590. #else
  591.   #ifdef TIOCGSIZE
  592.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  593.     if( ( !screenHeight || !screenWidth ) && ioctl( fileno( stderr ), TIOCGSIZE, &windowInfo ) != -1 )
  594.         {
  595.         if( !screenHeight && windowInfo.ts_lines > 0 )
  596.             screenHeight = ( int ) windowInfo.ts_lines;
  597.  
  598.         if( !screenWidth && windowInfo.ts_cols > 0 )
  599.             screenWidth = ( int ) windowInfo.ts_cols;
  600.         }
  601.   #else
  602.     #ifdef WIOCGETD
  603.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  604.     if( ( !screenHeight || !screenWidth ) && ioctl( fileno( stderr ), WIOCGETD, &windowInfo) != -1 )
  605.         {
  606.         if( !screenHeight && windowInfo.uw_height > 0 )
  607.             screenHeight = ( int ) ( windowInfo.uw_height / windowInfo.uw_vs );
  608.  
  609.         if( !screenWidth && windowInfo.uw_width > 0 )
  610.             screenWidth = ( int ) ( windowInfo.uw_width / windowInfo.uw_hs );
  611.         }    /* You are in a twisty maze of standards, all different */
  612.     #endif /* WIOCGETD */
  613.   #endif /* TIOCGSIZE */
  614. #endif /* TIOCGWINSZ */
  615.  
  616. #ifdef USE_TERMCAP
  617.     /* See what terminfo/termcap has to say */
  618.     if( !screenHeight || !screenWidth )
  619.         {
  620.         if( ( termInfo = getenv( "TERM" ) ) == NULL )
  621.             termInfo = UNKNOWN_TERM;
  622.  
  623.         if( ( tgetent( termBuffer, termInfo ) <= 0 ) )
  624.             strcpy( termBuffer, DUMB_TERMBUF );
  625.  
  626.         if( !screenHeight && ( rowTemp = tgetnum( "li" ) ) > 0 )
  627.                 screenHeight = ( int )rowTemp;
  628.  
  629.         if( !screenWidth && ( colTemp = tgetnum( "co" ) ) > 0 )
  630.                 screenWidth = ( int ) colTemp;
  631.     }
  632. #endif /* USE_TERMCAP */
  633.  
  634.     /* Use 80x24 if all else fails */
  635.     if( !screenHeight )
  636.         screenHeight = DEFAULT_ROWS;
  637.     if( !screenWidth )
  638.         screenWidth = DEFAULT_COLS;
  639.     }
  640.  
  641. int getCountry( void )
  642.     {
  643.     return( 0 );    /* Default to US - not very nice */
  644.     }
  645.  
  646. #if defined( POSIX )
  647.  
  648. int htruncate( const FD theFD )
  649.     {
  650.     return( ( ltrunc( theFD, 0L, SEEK_CUR ) == 0L ) ? IO_ERROR : OK );
  651.     }
  652.  
  653. #elif defined( AIX ) || defined( AIX370 ) || defined( AIX386 ) || \
  654.       defined( IRIX ) || defined( LINUX ) || defined( ULTRIX ) || \
  655.       defined( ULTRIX_OLD ) || defined( SUNOS )
  656.  
  657. int htruncate( const FD theFD )
  658.     {
  659.     return( ftruncate( theFD, tell( theFD ) ) );
  660.     }
  661.  
  662. #else
  663.  
  664. /* No two htruncate()'s are the same, so we make sure everyone gets an error
  665.    here so they must define one they can use */
  666.  
  667. #error "Need to implement/define htruncate in UNIX.C"
  668.  
  669. /* The worst-case htruncate() - open a new file, copy everything across to
  670.    the truncation point, and delete the old file.  This only works because
  671.    htruncate is almost never called, because this worst-case version will
  672.    only be used on a few systems, and because the drive access speed is
  673.    assumed to be fast */
  674.  
  675. void moveData( const FD _inFD, const FD destFD, const long noBytes );
  676.  
  677. int htruncate( const FD theFD )
  678.     {
  679.     FD newArchiveFD;
  680.     char newArchiveName[ MAX_PATH ];
  681.     long truncatePoint;
  682.     int retVal;
  683.  
  684.     /* Set up temporary filename to be the archive name with a ".TMP" suffix */
  685.     strcpy( newArchiveName, archiveFileName );
  686.     strcpy( newArchiveName, strlen( newArchiveName ) - 3, "TMP" );
  687.  
  688.     if( ( newArchiveFD = hopen( newArchiveName, O_RDWR ) ) == FILE_ERROR )
  689.         error( INTERNAL_ERROR );
  690.     setOutputFD( newArchiveFD );
  691.     setInputFD( archiveFD );
  692.  
  693.     /* Use the moveData() routine to move all data up to the truncation point
  694.        to the new archive */
  695.     truncatePoint = htell( archiveFD );
  696.     hlseek( archiveFD, 0L, SEEK_SET );
  697.     _outByteCount = 0;
  698.     moveData( truncatePoint );
  699.  
  700.     /* Close and delete the old archive, and make the new archive the active
  701.        one */
  702.     retVal = hclose( archiveFD );
  703.     archiveFD = newArchiveFD;
  704.     retVal |= hunlink( archiveFileName );
  705.     return( retVal | hrename( newArchiveName, archiveName ) );
  706.     }
  707. #endif /* Various mutation-dependant truncate()'s */
  708.  
  709. /* Check whether two pathnames refer to the same file */
  710.  
  711. BOOLEAN isSameFile( const char *pathName1, const char *pathName2 )
  712.     {
  713.     struct stat statInfo1, statInfo2;
  714.  
  715.     stat( pathName1, &statInfo1 );
  716.     stat( pathName2, &statInfo2 );
  717.     return( statInfo1.st_ino == statInfo2.st_ino && \
  718.             statInfo1.st_dev == statInfo2.st_dev );
  719.     }
  720.  
  721. #ifdef NEED_STRLWR
  722.  
  723. /* strlwr() for those systems which don't have it */
  724.  
  725. void strlwr( char *string )
  726.     {
  727.     while( *string )
  728.         {
  729.         *string = tolower( *string );
  730.         string++;
  731.         }
  732.     }
  733. #endif /* NEED_STRLWR */
  734.  
  735. #ifdef NEED_MEMMOVE
  736.  
  737. /* memmove() for those systems which don't have it */
  738.  
  739. void memmove( char *dest, char *src, int length )
  740.     {
  741.     int itmp = ( length + 7 ) >> 3;
  742.  
  743.     if( dest > src )
  744.         {
  745.         dest += length;
  746.         src += length;
  747.         switch( length & 3 )
  748.             {
  749.             case 0:    do {    *--dest = *--src;
  750.             case 7:            *--dest = *--src;
  751.             case 6:            *--dest = *--src;
  752.             case 5:            *--dest = *--src;
  753.             case 4:            *--dest = *--src;
  754.             case 3:            *--dest = *--src;
  755.             case 2:            *--dest = *--src;
  756.             case 1:            *--dest = *--src;
  757.                      } while( --itmp > 0 );
  758.             }
  759.         }
  760.     else
  761.         {
  762.         switch( length & 3 )
  763.             {
  764.             case 0:    do {    *dest++ = *src++;
  765.             case 7:            *dest++ = *src++;
  766.             case 6:            *dest++ = *src++;
  767.             case 5:            *dest++ = *src++;
  768.             case 4:            *dest++ = *src++;
  769.             case 3:            *dest++ = *src++;
  770.             case 2:            *dest++ = *src++;
  771.             case 1:            *dest++ = *src++;
  772.                      } while( --itmp > 0 );
  773.             }
  774.         }
  775.     /* This was added mainly to frighten you */
  776.     }
  777. #endif /* NEED_MEMMOVE */
  778.  
  779. #ifdef NEED_STRNICMP
  780.  
  781. int strnicmp( char *src, char *dest, int length )
  782.     {
  783.     char srcCh, destCh;
  784.  
  785.     while( length-- )
  786.         {
  787.  
  788.         /* Need to be careful with toupper() side-effects */
  789.         srcCh = *src++;
  790.         srcCh = toupper( srcCh );
  791.         destCh = *dest++;
  792.         destCh = toupper( destCh );
  793.  
  794.         if( srcCh != destCh )
  795.             return( srcCh - destCh );
  796.         }
  797.  
  798.     return( 0 );
  799.     }
  800.  
  801. #endif /* NEED_STRNICMP */
  802.